﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using AnjLab.SyncIT.Core.Api;
using AnjLab.SyncIT.Core.Data.Outlook;
using AnjLab.SyncIT.Core.Data.Trac;

namespace AnjLab.SyncIT.Core.Data.Trac
{
    public class TracTicketDao : ISourceTaskDao
    {
        private readonly string _tracXmlRpcUrl;
        private readonly NetworkCredential _credentials;
        private readonly Source _source;

        public TracTicketDao(Source source)
        {
            _source = source;
            _tracXmlRpcUrl = source.ProjectBase + "/login/xmlrpc";
            _credentials = new NetworkCredential(source.UserName, source.GetPassword());
        }

        public void Dispose()
        {
        }

        public ISourceTask Get(string id) {
            var request = GetRequest();

            var stream = request.GetRequestStream();

            using (var xml = new XmlTextWriter(stream, Encoding.UTF8))
            {
                var doc = new XDocument(
                    new XElement("methodCall",
                                 new XElement("methodName", "ticket.get"),
                                 new XElement("params",
                                              new XElement("param", new XElement("value", id)))));

                doc.WriteTo(xml);
            }

            using (var response = (HttpWebResponse)request.GetResponse())
            using (var sr = new StreamReader(response.GetResponseStream())) {
                var result = sr.ReadToEnd();

                var xmlTicket = XDocument.Parse(result)
                    .Element("methodResponse")
                    .Element("params")
                    .Element("param")
                    .Element("value")
                    .Element("array")
                    .Element("data");
                return Ticket.From(xmlTicket);
            }
        }

        public bool CanTrackTaskLifetime
        {
            get { return true; }
        }

        public void CheckConnection()
        {
            WebRequest request = GetRequest();
            
            request.ContentType = null;
            request.Method = "GET";
            
            using (var response = (HttpWebResponse)request.GetResponse())
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                string html = sr.ReadToEnd();

                if (html.Contains("No handler matched request to /login/xmlrpc"))
                {
                    throw new InvalidOperationException("Specified Trac environment doesn't have XML-RPC plugin installed");
                }

                if (! html.Contains("XML-RPC exported functions"))
                {
                    throw new InvalidOperationException("Invalid Trac environment");
                }
            }

        }

        public string []  GetChangedTasks() {
            var since = _source.SyncTimestamp;

            var request = GetRequest();

            var stream = request.GetRequestStream();
            
            using (var xml = new XmlTextWriter(stream, Encoding.UTF8))
            {
                var doc = new XDocument(
                    new XElement("methodCall",
                                 new XElement("methodName", "ticket.getRecentChanges"),
                                 new XElement("params",
                                              new XElement("param", new XElement("value", new XElement("dateTime.iso8601", since.ToUniversalTime().ToString("yyyyMMddTHH:mm:ss")))))));

                doc.WriteTo(xml);
            }
            var result = new List<string>();
            using (var response = (HttpWebResponse)request.GetResponse())
            using (var sr = new StreamReader(response.GetResponseStream())) {
                var xmlIDs = XDocument.Parse(sr.ReadToEnd())
                    .Element("methodResponse")
                    .Element("params")
                    .Element("param")
                    .Element("value")
                    .Element("array")
                    .Element("data");
                foreach (var xElement in xmlIDs.Elements()) {
                    result.Add(xElement.Value);
                }
            }
            return result.ToArray();
        }

        private HttpWebRequest GetRequest() {
            var request = (HttpWebRequest)WebRequest.Create(_tracXmlRpcUrl);

            request.Credentials = _credentials;
            request.Method = "POST";
            request.ContentType = "text/xml";
            return request;
        }

        public bool SupportsBackSynchronization
        {
            get { return false; }
        }

        public void MergeTasks(ISourceTask task, IOutlookItem outlookTask)
        {
            throw new NotSupportedException();
        }
   }
}